package  
{
	import bulletbehavior.AccelerateRelativeBehavior;
	import bulletbehavior.HomeTargetBehavior;
	import flash.geom.Rectangle;
	import org.flixel.*;
	/**
	 * ...
	 * @author morgan
	 */
	public class Player extends HitboxObject
	{
		[Embed (source = "../data/dog.png")] private var img_dog:Class;
		[Embed (source = "../data/dog_outline.png")] private var img_outline:Class;
		[Embed (source = "../data/tutorial_fat.png")] private var img_tut_grow:Class;
		
		public var SPEED:Number = 120;	// Movement speed in pixels / sec
		public var SLOWSPEED:Number = 60;
		
		public var BULLETPATTERN:BulletPattern = new BulletPattern();
		public var MISSILEPATTERN:BulletPattern = new BulletPattern();
		public var initializedMissiles:Boolean = false;
		
		public var currentSpeed:Number = 100;
		
		public var absorbRange:Number = 20;
		
		public var fireDelay:Number = 0;
		
		public var hitTimer:Number = 0;
		public var eatTimer:Number = 0;
		public var eaten:int = 0;
		
		public var appetite:Number = 0;
		
		public var beamTimer:Number = 0;
		public var thrusterTimer:Number = 0;
		
		public var nearFood:FlxSprite;
		
		public var curSizeStr:String = "0_";
		
		public var eye1X:Number = 0;
		public var eye2X:Number = 0;
		public var eye1Y:Number = 0;
		public var eye2Y:Number = 0;
		
		public var outline:FlxSprite;
		
		public var appetiteCooldown:Number = 0;
		public var swapCooldown:Number = 0;
		
		public var throwBoneTimer:Number = 0;
		public var throwBone:Boolean = false;
		
		public var spinTimer:Number = 0;
		
		public var dying:Boolean = false;
		public var appetiteScoreCooldown:Number = 0;
		
		public function Player(x:int, y:int) 
		{
			super(x, y);
			loadGraphic(img_dog, true, false, 50, 50);
			
			outline = new FlxSprite(0, 0);
			outline.loadGraphic(img_outline, true, false, 50, 50);
			
			outline.color = 0xfff600;
			
			for (var size:int = 0; size < 4; size++)
			{
				var sstr:String = size.toString() + "_";
				var idleFrames:Array = [];
				for (var i:int = 0; i < 30; i++)
				{
					idleFrames.push(size * 5 + int(Math.random() * 3));
				}
				
				addAnimation(sstr + "idle", idleFrames, 3, true);
				addAnimation(sstr + "eat", [size * 5 + 3, size * 5 + 1], 10);
				addAnimation(sstr + "hit", [size * 5 + 4, size * 5 + 1], 10);
			}
				
			play(curSizeStr + "idle");
			
			// Bullet hell = tiny hitbox
			offset.x = width / 2 - HITBOX / 2;
			offset.y = height / 2 - HITBOX / 2;
			width = HITBOX; height = HITBOX;
			x -= HITBOX/2;
			y -= HITBOX / 2;
			
			health = 1;
			
			drawHitbox = 1;
		}
		
		override public function update():void 
		{
			if (dying)
			{
				if (spinTimer > 0.1)
				{
					angle += 90;
					spinTimer = 0;
				}
				spinTimer += FlxG.elapsed;
				velocity.x = 0;
				velocity.y = 60;
				super.update();
				if (y > 280)
				{
					FlxG.fade(0xff000000, 1, fadeFinish);
				}
				return;
			}
			appetiteCooldown -= FlxG.elapsed;
			updateMovement();
			updateModeSwitch();
			if (!GameState.ref.boss.dying)
			{
				if (throwBone && throwBoneTimer < 0)
				{
					fire();
					throwBone = false;
				}
				throwBoneTimer -= FlxG.elapsed;
			}
			updateAbsorption();
			
			if (GameState.ref.boss && !initializedMissiles)
			{
				MISSILEPATTERN.addBehavior(new HomeTargetBehavior(GameState.ref.boss, Math.PI * 2), 0.25);
				MISSILEPATTERN.addBehavior(new AccelerateRelativeBehavior(-10, 0));
				initializedMissiles = true;
			}
			
			hitTimer -= FlxG.elapsed;
			eatTimer -= FlxG.elapsed;
			if (hitTimer > 0)
			{
				play(curSizeStr + "hit");
			}
			else if (eatTimer > 0)
			{
				play(curSizeStr + "eat");
			}
			else
			{
				play(curSizeStr + "idle");
			}
			
			//scale.x = scale.y = health / 2 + 0.5;
			currentSpeed = (GameState.shiftHitbox ? SLOWSPEED : SPEED) / (health / 8 + 0.75);
			absorbRange = 15 + health * 3;
			
			curSizeStr = (health - 1).toString() + "_";
			
			if (health == 1) { eye1X = -4.55; eye2X = 6.55; eye1Y = 1; eye2Y = 2; }
			if (health == 2) { eye1X = -6.55; eye2X = 8.55; eye1Y = 2; eye2Y = 3; }
			if (health == 3) { eye1X = -9.55; eye2X = 11.55; eye1Y = 3; eye2Y = 4; }
			if (health == 4) { eye1X = -12.55; eye2X = 14.55; eye1Y = 4; eye2Y = 5; }
			
			thrusterTimer -= FlxG.elapsed;
			if (thrusterTimer <= 0)
			{
				thrusterTimer = 0.1;
				GameState.ref.makeParticle(Particle.THRUSTER2, x + Math.random() * 5 - 8, y + Math.random() * 5 - 8);
				GameState.ref.makeParticle(Particle.THRUSTER2, x + Math.random() * 5 - 8, y + Math.random() * 5 + 8);
				GameState.ref.makeParticle(Particle.THRUSTER2, x + Math.random() * 5 + 8, y + Math.random() * 5 + 8);
				GameState.ref.makeParticle(Particle.THRUSTER2, x + Math.random() * 5 + 8, y + Math.random() * 5 - 8);
			}
			
			super.update();
		}
		
		override public function postUpdate():void 
		{
			super.postUpdate();
			boundMotion();
			if (beamTimer > 0)
			{
				beamTimer -= FlxG.elapsed;
				GameState.ref.rainbowBeam.x = x - 10;
				GameState.ref.rainbowBeam.y = y - 240;
				GameState.ref.rainbowBeam.exists = true;
				FlxG.shake(0.004, 0.1);
				appetiteCooldown = 10.0;
			}
			else
			{
				GameState.ref.rainbowBeam.exists = false;
			}			
			
			GameState.ref.playerShadow.x = x - 154;
			GameState.ref.playerShadow.y = y - 94;
					
		}
		
		public function fire():void
		{
			if (fireDelay <= 0)
			{
				var r:Number = Math.random() * 6.2818;
				GameState.ref.makeBullet(Bullet.PLAYER, x, y, Math.cos(r) * 150, Math.sin(r) * 150, MISSILEPATTERN);
				fireDelay = 0.5;
				SoundAssets.playerFire.Play();
			}
			fireDelay = 0;
			//fireDelay -= FlxG.elapsed;
		}
		
		public function updateModeSwitch():void
		{
			if (FlxG.keys.justPressed("SPACE") && !GameState.ref.spaceDisabled && !GameState.ref.tutorial && swapCooldown < 0)
			{
				SoundAssets.swap.Play();
				GameState.ref.cycleMode();
				
				if (GameState.ref.mode == Bullet.BREAKFAST) { outline.color = 0xfff600; }
				if (GameState.ref.mode == Bullet.LUNCH) { outline.color = 0xff0000; }
				if (GameState.ref.mode == Bullet.DINNER) { outline.color = 0x2452ff; }
				
				if (appetite >= 100)
				{
					beamTimer = 2.5;
				}
				appetite = 0;
				swapCooldown = 0.25;
				GameState.ref.effectTransitionTime = 0.0;
			}
			swapCooldown -= FlxG.elapsed;
		}
		
		public function absorb(amount:int = 1):void
		{
			//throwBone = true;
			//throwBoneTimer = 0;
			fire();
			eatTimer = 0.5;
			if (health < 4)
			{
				eaten += amount;
				if (eaten > 19 && !GameState.ref.growingDisabled)
				{
					eaten = 0;
					health++
					if (!Saving.hasGrown)
					{
						GameState.ref.showTutorial(img_tut_grow);
						Saving.hasGrown = true;
					}
					GameState.hitboxes = 1.0;
					GameState.ref.multBump = 1.0;
				}
			}
		}
		
		public function getHit():void
		{
			if (hitTimer > 0) { return; }
			health--;
			if (health <= 0)
			{
				dying = true;
				GameState.ref.bossDialog.showLoss();
				FlxG.flash(0xffff0000, 0.2);
				SoundAssets.playerDie.Play();
			}
			else
			{
				GameState.hitboxes = 1.0;
				SoundAssets.hitPlayer.Play();
			}
			eaten = 0;
			FlxG.shake(0.01, 0.75);
			hitTimer = 0.75;
		}
		
		public function fadeFinish():void
		{
			GameState.ref.restart();
		}
		
		public function updateAbsorption():void
		{
			var bullets:Array = GameState.ref.bullets.members;
			nearFood = null;
			var nearDist:Number = 50 * 50;
			var numNear:int = 0;
			for (var i:int = 0; i < bullets.length; i++)
			{
				if (bullets[i] && bullets[i].exists)
				{
					var dx:Number = (bullets[i].x + bullets[i].width / 2) - (x + width / 2);
					var dy:Number = (bullets[i].y + bullets[i].height / 2) - (y + height / 2);
					var dist:Number = dx * dx + dy * dy;	
					if (dist < nearDist) { nearDist = dist; nearFood = bullets[i]; }
					if (dist < absorbRange * absorbRange)
					{	
						if (bullets[i].type == GameState.ref.mode)
						{			
							if (bullets[i].scale.x > 1.5)
							{
								absorb(20);
							}
							else
							{
								absorb();
							}
							bullets[i].exists = false;
							SoundAssets.eat.Play();
							GameState.ref.addScore(100, this);
						}						
						else if (bullets[i].type != Bullet.PLAYER)
						{
							if (bullets[i].type == Bullet.CANDY)
							{
								absorb(20);
								bullets[i].exists = false;
								SoundAssets.eat.Play();
								GameState.ref.addScore(500, this);								
							}
							if (appetite < 100 && appetite + 50 * FlxG.elapsed >= 100)
							{
								SoundAssets.appetite.Play();
								appetite = 100;
							}							
							if (bullets[i].type != Bullet.ROTTEN)
							{
								numNear++
								if (numNear < 2 && appetiteCooldown <= 0 && !GameState.ref.spaceDisabled)
								{
									appetite = Math.min(appetite + 30 * FlxG.elapsed, 100);
									if (appetiteScoreCooldown < 0)
									{
										GameState.ref.addScore(20, this);
										appetiteScoreCooldown = 0.25;
									}
									appetiteScoreCooldown -= FlxG.elapsed;
								}
							}
							bullets[i].drawHitbox = GameState.hitboxes
							GameState.hitboxes = Math.max(Math.min(GameState.hitboxes + FlxG.elapsed * 2, 1.5), 0.25);
						}						
					}
				}
			}
		}
		
		public function updateMovement():void
		{
			var vx:Number = 0; var vy:Number = 0;
			if (FlxG.keys.LEFT) { vx = -1; }
			if (FlxG.keys.RIGHT) { vx = 1; }
			if (FlxG.keys.UP) { vy = -1; }
			if (FlxG.keys.DOWN) { vy = 1; }
			
			// If you're moving diagonally, sqrt(2)/2 for each component.
			if (Math.abs(vx) > 0 && Math.abs(vy) > 0) { vx *= 0.707; vy *= 0.707; }
			
			velocity.x = vx * currentSpeed;
			velocity.y = vy * currentSpeed;
		}
		
		// Limit motion based on the playing field size.	
		public function boundMotion():void
		{
			if (dying) { return; }
			x = FlxU.bound(x, GameState.FIELDLEFT + HITBOX / 2, (GameState.FIELDLEFT + GameState.FIELDWIDTH) - HITBOX / 2);
			y = FlxU.bound(y, 70 + HITBOX / 2,FlxG.height - HITBOX / 2);
		}
		
		override public function draw():void 
		{
			if (dying) { super.draw(); return; }
			var dx:Number = int(x);
			var dy:Number = int(y);
			
			outline.x = dx - offset.x;
			outline.y = dy - offset.y;
			outline.draw();
			outline.frame = frame;
			
			super.draw();
			
			// Meter to show appetite
			/*var w:Number = appetite * 20 / 100.0;
			FlxG.camera.buffer.fillRect(new Rectangle(x + width/2 - 11, y + offset.y + 1, 22, 4), 0xff000000);
			FlxG.camera.buffer.fillRect(new Rectangle(x + width/2 - 10, y + offset.y + 2, w, 2), 0xffffffff);
			*/
			
			if (nearFood != null)
			{
				dx = (x + width / 2) - (nearFood.x + nearFood.width / 2);
				dy = (y + height / 2) - (nearFood.y + nearFood.height / 2);
				var dist:Number = Math.sqrt(dx * dx + dy * dy);
				dx *= -1.5 / dist;
				dy *= -1.5 / dist;
				dx = FlxU.bound(dx, -0.5, 0.5);
				dy = FlxU.bound(dy, -0.5, 0.5);
				
				FlxG.camera.buffer.fillRect(new Rectangle(int(x) + int(eye1X + dx), int(y) + int(eye1Y + dy), 2, 2), 0xff000000);
				FlxG.camera.buffer.fillRect(new Rectangle(int(x) + int(eye2X + dx), int(y) + int(eye2Y + dy), 2, 2), 0xff000000);
				//FlxG.camera.buffer.fillRect(new Rectangle(int(x + -4.55 + dx), int(y + 0.5 + dy), 2, 2), 0xff000000);
			}
			else
			{
				FlxG.camera.buffer.fillRect(new Rectangle(int(x) + eye1X + 1, int(y) + eye1Y - 1, 2, 2), 0xff000000);
				FlxG.camera.buffer.fillRect(new Rectangle(int(x) + eye2X - 1, int(y) + eye2Y - 1, 2, 2), 0xff000000);
			}
		}
	}

}